import re

from django.contrib.auth import authenticate
from django_redis import get_redis_connection
from rest_framework import serializers
from django.contrib.auth.models import User
from rest_framework.serializers import ModelSerializer
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer, TokenRefreshSerializer

from config.dbs.redisConfig import KEY_TEMPLATE
from users.models import UserDetail, Area, Address


class UserSerializer(serializers.ModelSerializer):
    # 新增验证码和uuid字段
    # 反序列化的时候进行校验  允许写入
    verify = serializers.CharField(write_only=True)
    uuid = serializers.CharField(write_only=True)
    # user.userdetail.sex
    sex = serializers.IntegerField(read_only=True,source="userdetail.sex")
    birthday = serializers.DateField(read_only=True,source="userdetail.birthday")
    phone = serializers.CharField(read_only=True,source="userdetail.phone")
    avatar = serializers.CharField(read_only=True,source="userdetail.avatar")
    class Meta:
        model = User
        # fields = '__all__'

        # 序列化的时候不展示  反序列化的时候 也不能输入
        exclude = [ 'is_superuser', 'is_staff', 'is_active', 'user_permissions']

        #
        extra_kwargs = {
            # 设置反序列化的时候 只能写入
            'password': {"write_only": True},
        }

    # 当客户端发送127.0.0.1:8000/user/verification/register
    # 客户端返回验证码图片     redis  存储键值对  key（uuid）:验证码

    # 对象级别的校验
    def validate(self, attrs):
        uuid = attrs.get('uuid')
        verify = attrs.get('verify')

        # 获取redis缓存信息
        cache = get_redis_connection(alias="verify_codes")
        redis_verify = cache.get(KEY_TEMPLATE % ("register", uuid))
        # 客户端获取一次验证码，数据库得到验证码  之后就删除数据库的中的验证码信息
        cache.delete(KEY_TEMPLATE %  ("register", uuid))
        # 判断redis数据库中 是否存在这个键值对
        if not redis_verify:
            raise serializers.ValidationError("验证码不存在")
        # 忽略大小写验证验证码是否一致
        if verify.upper() != redis_verify.upper():
            raise serializers.ValidationError("验证码错误")
        return attrs


# 登录的校验序列化器
class MyTokenObtainSerializer(TokenObtainPairSerializer):
    # 有没有对应的模型表
    # 登录到时候 可以通过客户端 传入 uuid 和 验证码
    verify = serializers.CharField(write_only=True)
    uuid = serializers.CharField(write_only=True)

    # TokenObtainPairSerializer 校验账号和密码  返回 token
    # 校验 验证码 uuid
    # 对象级别的校验
    # 客户端传入的数据 都在 attrs {uuid:"",verify:"",username:"",password:""}
    def validate(self, attrs):
        # 得到客户端传入的uuid
        uuid = attrs.get('uuid')
        verify = attrs.get('verify')
        username = attrs.get('username')
        password = attrs.get('password')

        # 获取数据库端的数据
        # 获取redis缓存信息
        cache = get_redis_connection(alias="verify_codes")
        redis_verify = cache.get(KEY_TEMPLATE % ("login", uuid))
        # 客户端获取一次验证码，数据库得到验证码  之后就删除数据库的中的验证码信息
        cache.delete(KEY_TEMPLATE %  ("login", uuid))
        # 判断redis数据库中 是否存在这个键值对
        if not redis_verify:
            raise serializers.ValidationError("验证码不存在")
        # 忽略大小写验证验证码是否一致
        if verify.upper() != redis_verify.upper():
            raise serializers.ValidationError("验证码错误")

        # 身份校验
        user = authenticate(username=username, password=password)
        if not user:
            # 账号或者密码不对
            raise serializers.ValidationError("账号或者密码不对")
        # 制作token令牌
        refresh = self.get_token(user)

        # 返回的数据信息

        return {"user":user.username,"token":str(refresh.access_token)}


# 用户详情的序列化器
class UserDetailSerializer(ModelSerializer):
        class Meta:
            model = UserDetail
            exclude = ["is_delete"]

# 修改密码的序列化器
class UpdatePasswordSerializer(serializers.Serializer):
    # 有存在的模型的时候  ModelSerializer
    # 没有单独的密码表
    # 新增要进行校验的字段
    # 在进行接口相应  序列化的时候 客户端能够看得到这些数据
    password = serializers.CharField(max_length=100)
    new_password = serializers.CharField(max_length=100)
    re_new_password = serializers.CharField(max_length=100)
    # 校验
    # 对象级别的校验
    # attrs = {"password":,"new_password":,"re_password":}
    def validate(self, attrs):
        if attrs["new_password"] != attrs["re_new_password"]:
            raise serializers.ValidationError("两次密码不一致")

        # 判断原密码和新密码是否是同一个
        if attrs["new_password"] == attrs["password"]:
            raise serializers.ValidationError("新密码不能和原密码一样")



        return attrs



# 地址序列化器
class AreaSerializer(serializers.ModelSerializer):
    class Meta:
        model = Area
        fields = ["id","name"]


# 子级地区的序列化器
class ParentAreaSerializer(serializers.ModelSerializer):
    area_set = AreaSerializer(many=True, read_only=True)
    class Meta:
        model = Area
        fields = ["id","name","area_set"]

# 详情地址序列化器
class AddressSerializer(serializers.ModelSerializer):
    province_name = serializers.CharField(source="province.name",read_only=True)
    city_name = serializers.CharField(source="city.name",read_only=True)
    district_name = serializers.CharField(source="district.name",read_only=True)
    class Meta:
        model = Address
        # fields = "__all__"
        exclude = ["is_delete"]

    # 补充点
    # 手机号怎么校验

    def validate_mobile(self,value):
        if not re.match(r"1[3-9]\d{9}",value):
            raise serializers.ValidationError("手机号格式不符")
        return value


